// 手写promise

// Promise 的三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class Promise {
  constructor(executor) {
    // 初始化状态为 pending
    this.status = PENDING;
    // 存储成功状态的值
    this.value = undefined;
    // 存储失败状态的原因
    this.reason = undefined;
    // 存储成功回调函数队列
    this.onFulfilledCallbacks = [];
    // 存储失败回调函数队列
    this.onRejectedCallbacks = [];

    // 成功回调
    const resolve = (value) => {
      // 如果 value 是 Promise 则递归解析
      if (value instanceof Promise) {
        return value.then(resolve, reject);
      }

      // 只有状态是 pending 时才能转变为 fulfilled
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.value = value;
        // 执行所有成功回调
        this.onFulfilledCallbacks.forEach((callback) => callback());
      }
    };

    // 失败回调
    const reject = (reason) => {
      // 只有状态是 pending 时才能转变为 rejected
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        // 执行所有失败回调
        this.onRejectedCallbacks.forEach((callback) => callback());
      }
    };

    try {
      // 立即执行执行器函数
      executor(resolve, reject);
    } catch (error) {
      // 如果执行器抛出异常，将 Promise 状态变为 rejected
      reject(error);
    }
  }

  // then 方法接收两个参数，分别是成功和失败的回调
  then(onFulfilled, onRejected) {
    // 处理参数默认值，确保一定是函数
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (value) => value;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason;
          };

    // 返回一个新的 Promise，以实现链式调用
    const promise2 = new Promise((resolve, reject) => {
      // 封装微任务处理逻辑
      const handleMicrotask = (callback, data, resolve, reject) => {
        // 使用 queueMicrotask 或 setTimeout 模拟微任务
        queueMicrotask(() => {
          try {
            const x = callback(data);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      };

      if (this.status === FULFILLED) {
        // 成功状态下立即异步执行成功回调
        handleMicrotask(onFulfilled, this.value, resolve, reject);
      } else if (this.status === REJECTED) {
        // 失败状态下立即异步执行失败回调
        handleMicrotask(onRejected, this.reason, resolve, reject);
      } else if (this.status === PENDING) {
        // pending 状态下，将回调函数存入对应队列
        this.onFulfilledCallbacks.push(() => {
          handleMicrotask(onFulfilled, this.value, resolve, reject);
        });
        this.onRejectedCallbacks.push(() => {
          handleMicrotask(onRejected, this.reason, resolve, reject);
        });
      }
    });

    return promise2;
  }

  // 解析 Promise 的方法，处理链式调用
  resolvePromise(promise2, x, resolve, reject) {
    // 如果返回值是当前 promise，会导致循环引用，需要抛出错误
    if (promise2 === x) {
      return reject(new TypeError("Chaining cycle detected for promise"));
    }

    // 防止多次调用
    let called = false;

    // 如果 x 是对象或函数
    if ((x !== null && typeof x === "object") || typeof x === "function") {
      try {
        // 尝试获取 then 方法
        const then = x.then;

        // 如果 then 是函数，说明 x 是 Promise 或 thenable 对象
        if (typeof then === "function") {
          // 调用 then 方法，将 resolvePromise 和 rejectPromise 作为回调函数
          then.call(
            x,
            // resolvePromise
            (y) => {
              if (called) return;
              called = true;
              // 递归解析，直到获取到一个非 Promise 值
              this.resolvePromise(promise2, y, resolve, reject);
            },
            // rejectPromise
            (r) => {
              if (called) return;
              called = true;
              reject(r);
            }
          );
        } else {
          // 如果 then 不是函数，则直接 resolve x
          resolve(x);
        }
      } catch (error) {
        if (called) return;
        called = true;
        reject(error);
      }
    } else {
      // 如果 x 不是对象或函数，直接 resolve
      resolve(x);
    }
  }

  // catch 方法用于捕获异常，相当于 then(null, onRejected)
  catch(onRejected) {
    return this.then(null, onRejected);
  }

  // finally 方法无论成功或失败都会执行
  finally(callback) {
    return this.then(
      (value) => Promise.resolve(callback()).then(() => value),
      (reason) =>
        Promise.resolve(callback()).then(() => {
          throw reason;
        })
    );
  }

  // 静态 resolve 方法
  static resolve(value) {
    if (value instanceof Promise) return value;
    return new Promise((resolve) => resolve(value));
  }

  // 静态 reject 方法
  static reject(reason) {
    return new Promise((resolve, reject) => reject(reason));
  }

  // 静态 all 方法，所有 Promise 都成功才成功，有一个失败就失败
  static all(promises) {
    if (!Array.isArray(promises)) {
      throw new TypeError("promises must be an array");
    }

    return new Promise((resolve, reject) => {
      const results = [];
      let count = 0;

      // 如果传入的是空数组，则直接返回空数组
      if (promises.length === 0) return resolve(results);

      promises.forEach((promise, index) => {
        Promise.resolve(promise).then((value) => {
          results[index] = value;
          count++;
          // 所有 Promise 都成功后，返回结果数组
          if (count === promises.length) resolve(results);
        }, reject);
      });
    });
  }

  // 静态 race 方法，返回最先完成的 Promise 结果
  static race(promises) {
    if (!Array.isArray(promises)) {
      throw new TypeError("promises must be an array");
    }

    return new Promise((resolve, reject) => {
      // 空数组会一直等待
      promises.forEach((promise) => {
        Promise.resolve(promise).then(resolve, reject);
      });
    });
  }

  // 静态 allSettled 方法，等待所有 Promise 完成（无论成功或失败）
  static allSettled(promises) {
    if (!Array.isArray(promises)) {
      throw new TypeError("promises must be an array");
    }

    return new Promise((resolve) => {
      const results = [];
      let count = 0;

      if (promises.length === 0) return resolve(results);

      promises.forEach((promise, index) => {
        Promise.resolve(promise).then(
          (value) => {
            results[index] = { status: "fulfilled", value };
            count++;
            if (count === promises.length) resolve(results);
          },
          (reason) => {
            results[index] = { status: "rejected", reason };
            count++;
            if (count === promises.length) resolve(results);
          }
        );
      });
    });
  }
}

export default Promise;
